#include "connectorentity.h"
#include <QPen>
#include <QPainter>
#include <QDebug>
#include <QPolygonF>
#include <QtMath>
#include <QStyleOptionGraphicsItem>
#include <QGraphicsScene>
#include "../aurasim.h"

ConnectorEntity::ConnectorEntity(QGraphicsItem *parent, PinEntity* start, PinEntity* end):
    Entity (parent),
    mStartPin(start),
    mEndPin(end),
    mLineWidth(6)
{
    setName("Connector");

    start->setConnected(true);
    end->setConnected(true);

    mStartDirection = mStartPin->pinDirection();
    mEndDirection = mEndPin->pinDirection();
    mStartPoint = mStartPin->scenePos() - this->scenePos();
    mEndPoint = mEndPin->scenePos() - this->scenePos();

    mStartPin->addConnector(id());
    mEndPin->addConnector(id());

    setFlags(ItemIsSelectable);
    initConnections();
}

QRectF ConnectorEntity::boundingRect() const
{
    return shape().boundingRect();
}

void ConnectorEntity::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(widget)
    QPen pen;
    pen.setCapStyle(Qt::RoundCap);
    pen.setWidth(mLineWidth / 2);
    QColor drawColor(160, 170, 100);
    drawColor.setAlpha(150);
    if(option->state & QStyle::State_MouseOver || option->state & QStyle::State_Selected){
        drawColor = drawColor.lighter(180);
        drawColor.setAlpha(180);
    }

    pen.setColor(drawColor);
    painter->setPen(pen);
    painter->drawPath(shape());
}

QPainterPath ConnectorEntity::shape() const
{
    // ensure that this connector has either input pin or output pin
    QPainterPath path;

    QPointF c1 = mStartPoint;
    QPointF c2 = mEndPoint;

    if (mStartDirection == PinDirection::Up)
        c1 = QPointF(mStartPoint.x(), mStartPoint.y() - 40);
    if (mStartDirection == PinDirection::Down)
        c1 = QPointF(mStartPoint.x(), mStartPoint.y() + 40);
    if (mStartDirection == PinDirection::Right)
        c1 = QPointF(mStartPoint.x() + 40, mStartPoint.y());
    if (mStartDirection == PinDirection::Left)
        c1 = QPointF(mStartPoint.x() - 40, mStartPoint.y());

    if (mEndDirection == PinDirection::Up)
        c2 = QPointF(mEndPoint.x(), mEndPoint.y() - 40);
    if (mEndDirection == PinDirection::Down)
        c2 = QPointF(mEndPoint.x(), mEndPoint.y() + 40);
    if (mEndDirection == PinDirection::Right)
        c2 = QPointF(mEndPoint.x() + 40, mEndPoint.y());
    if (mEndDirection == PinDirection::Left)
        c2 = QPointF(mEndPoint.x() - 40, mEndPoint.y());

    path.moveTo(mStartPoint);
    path.cubicTo(c1, c2, mEndPoint);
    return path;
}

void ConnectorEntity::removeSelf()
{
    mStartPin->removeConnector(id());
    mEndPin->removeConnector(id());
    mStartPin->removeCurrentNode(mEndPin->id());
    mEndPin->removeCurrentNode(mStartPin->id());
    Entity::removeSelf();
}

QJsonObject ConnectorEntity::toJsonObject()
{
    QJsonObject obj = Entity::toJsonObject();
    obj.insert("startID", mStartPin->id());
    obj.insert("endID", mEndPin->id());
    return obj;
}

void ConnectorEntity::tick(const int &msec)
{
    Q_UNUSED(msec)

    if(!isRemoved()){
        QPointF pos = mStartPin->scenePos() + (mEndPin->scenePos() - mStartPin->scenePos()) / 2;
        setPos(pos);
        prepareGeometryChange();
        mStartPoint = mStartPin->scenePos() - this->scenePos();
        mEndPoint = mEndPin->scenePos() - this->scenePos();

        if((mStartPin->pinMode() == 1 && mEndPin->pinMode() == 0) || (mStartPin->pinMode() != 2 && mEndPin->pinMode() == 2))
            mStartPin->addCurrentNode(mEndPin->id());

        if((mEndPin->pinMode() == 1 && mStartPin->pinMode() == 0) || (mEndPin->pinMode() != 2 && mStartPin->pinMode() == 2))
            mEndPin->addCurrentNode(mStartPin->id());
    }
}

void ConnectorEntity::initConnections()
{
    PinEntity* startPE = static_cast<PinEntity*>(mStartPin->parentObject());
    PinEntity* endPE = static_cast<PinEntity*>(mEndPin->parentObject());
    connect(startPE, &Entity::destroyed, this, &ConnectorEntity::onStartPinDestroy);
    connect(endPE, &Entity::destroyed, this, &ConnectorEntity::onEndPinDestroy);
}

void ConnectorEntity::onStartPinDestroy()
{
    mStartPin = nullptr;
    if (mEndPin) {
        mEndPin->removeConnector(id());
    }
    Entity::removeSelf();
}

void ConnectorEntity::onEndPinDestroy()
{
    mEndPin = nullptr;
    if(mStartPin)
        mStartPin->removeConnector(id());
    Entity::removeSelf();
}

void ConnectorEntity::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    Entity::mousePressEvent(event);
}
